import inspect
import json
from abc import abstractmethod, ABC
from pathlib import Path
from typing import TypeVar, Generic, Optional, Any, NamedTuple, Coroutine, Callable, List

import yaml

from ..jsonpat import from_json
from ..logger import AbstractLogger
from .request_handler import ContextType, HttpEndpointDescriptor
from .default_server import DefaultServer

ConfigType = TypeVar("ConfigType")


class ServerStartOptions(ABC, Generic[ContextType, ConfigType]):
    @property
    @abstractmethod
    def logger(self) -> AbstractLogger:
        pass

    @property
    @abstractmethod
    def entries(self) -> List[HttpEndpointDescriptor[ContextType]]:
        pass

    @abstractmethod
    async def on_create_context(self) -> ContextType:
        pass

    async def on_close(self, context: ContextType):
        if hasattr(context, "close"):
            await context.close()


class Stopper(NamedTuple):
    stop: Callable[[], Coroutine[Any, Any, None]]


async def run_default_server(
        options: ServerStartOptions[ContextType, ConfigType],
        port: int
):
    context = await options.on_create_context()

    server = await DefaultServer.create(
        logger=options.logger,
        handlers=options.entries,
        context=context,
        host="0.0.0.0",
        port=port
    )

    async def stop():
        await server.stop()
        await options.on_close(context)

    return Stopper(stop)
